<template>
  <view class="s-table" :class="c_class" :style="c_style">
    <scroll-view scroll-x>
      <view v-if="showHeader" class="s-table__header" :style="header_style">
        <template v-for="(column, columnIndex) of columns">
          <view
            v-if="!column.hidden"
            :key="columnIndex"
            class="s-table__th"
            :class="'' + getThClass(column, columnIndex)"
            :style="'' + getThStyle(column, columnIndex)"
            @click="onThClick(column, columnIndex)"
          >
            <view>{{ column.label }}</view>
            <view v-if="hasSort(column)" class="s-table__sort-wrap">
              <view
                v-for="order of ['asc', 'desc']"
                :key="order"
                class="s-table__sort-icon"
                :class="{ 's-table__sort-icon--active': isActiveSort(column, order) }"
                :style="{
                  color: isActiveSort(column, order) ? sortActiveColor : sortColor,
                }"
              ></view>
            </view>
          </view>
        </template>
      </view>
      <view class="s-table__body" :style="body_style">
        <scroll-view scroll-y>
          <view
            v-for="(row, rowIndex) of data"
            :key="rowIndex"
            class="s-table__tr"
            :class="'' + getRowClass(row, rowIndex)"
            :style="'' + getRowStyle(row, rowIndex)"
            @click="onTrClick(row, rowIndex)"
          >
            <template v-for="(column, columnIndex) of columns">
              <view
                v-if="!column.hidden"
                :key="columnIndex"
                class="s-table__td"
                :class="'' + getTdClass({ row, rowIndex, column, columnIndex })"
                :style="'' + getTdStyle({ row, rowIndex, column, columnIndex })"
                @click="onTdClick({ row, rowIndex, column, columnIndex })"
              >
                <slot
                  :scopeParams="scopeParams"
                  :row="row"
                  :rowIndex="rowIndex"
                  :column="column"
                  :columnIndex="columnIndex"
                >
                  {{ row[column.prop] }}
                </slot>
              </view>
            </template>
          </view>
        </scroll-view>
      </view>
    </scroll-view>
  </view>
</template>

<script>
import componentMixin from '../../mixins/componentMixin';

/**
 * s-table 简单数据表格
 * @description 简单的表格组件，可设每列宽度，内置排序功能
 * @property {Array} columns 表头 [{label, prop, minWidth, width，sortBy, hidden}]
 * @property {Array} data 数据列表
 * @property {String} align = [left|center|right] 文字居中方向
 * @property {Boolean} border 是否显示边框
 * @property {String} borderColor 边框颜色色
 * @property {String|Object} headerStyle 表头样式
 * @property {String|Object|Array|Function} rowClass 行 class rowClass(row, rowIndex)
 * @property {String|Object|Function} rowClass 行 style rowStyle(row, rowIndex)
 * @property {String|Object|Array|Function} thClass 表头单元格 class thClass(column, columnIndex)
 * @property {String|Object|Function} thStyle 表头单元格 style thStyle(column, columnIndex)
 * @property {String|Object|Array|Function} tdClass 单元格 class tdClass({ row, rowIndex, column, columnIndex })
 * @property {String|Object|Function} tdStyle 单元格 style tdStyle({ row, rowIndex, column, columnIndex })
 * @property {String|Number} sortBy 排序字段，sort-by.sync双向绑定用于获取
 * @property {String} sortOrder = [asc | desc] 排序顺序， sort-order.sync 双向绑定用于获取
 * @property {String} sortColor 排序icon颜色
 * @property {String} sortActiveColor 排序icon激活颜色
 * @event {Function} sort ({ row, rowIndex, column, columnIndex }) 触发排序时, 需要双向绑定获取 :sort-by.sync="sortBy" :sort-order.sync="sortOrder"
 * @event {Function} th-click (column, columnIndex) th点击事件
 * @event {Function} tr-click (row, rowIndex) tr点击事件
 * @event {Function} td-click ({ row, rowIndex, column, columnIndex }) td点击事件
 * @example <s-table border align="center" :columns="table.columns" :data="table.data" />
 */
export default {
  name: 'STable',
  mixins: [componentMixin],
  props: {
    columns: {
      type: Array,
      default: () => [],
    },
    data: {
      type: Array,
      default: () => [],
    },
    stripe: Boolean,
    height: [Number, String],
    align: String,
    border: Boolean,
    borderColor: String,
    showHeader: {
      type: Boolean,
      default: true,
    },
    headerStyle: [String, Object],
    rowClass: [String, Object, Array, Function],
    rowStyle: [String, Object, Function],
    thClass: [String, Object, Array, Function],
    thStyle: [String, Object, Function],
    tdClass: [String, Object, Array, Function],
    tdStyle: [String, Object, Function],
    sortBy: [Number, String],
    sortOrder: String,
    sortColor: String,
    sortActiveColor: String,
  },
  computed: {
    c_class() {
      return this.$mergeClass({
        's-table--border': this.border,
        's-table--stripe': this.stripe,
        [`s-table--align-${this.align}`]: this.align,
      }, this.custom_class);
    },
    c_style() {
      return this.$mergeStyle({
        borderColor: this.borderColor,
      }, this.custom_style);
    },
    header_style() {
      return this.$mergeStyle(this.headerStyle);
    },
    body_style() {
      return this.$mergeStyle({
        height: this.$addUnit(this.height),
      });
    },
  },
  methods: {
    hasSort(column) {
      return typeof column.sortBy !== 'undefined';
    },
    isActiveSort(column, sortOrder) {
      return this.sortBy === column.sortBy && this.sortOrder === sortOrder;
    },
    getColumnWidth(column) {
      const styles = {};
      if (typeof column.minWidth !== 'undefined') {
        styles.minWidth = this.$addUnit(column.minWidth);
      }
      if (typeof column.width !== 'undefined') {
        styles.width = this.$addUnit(column.width);
      } else {
        styles.flex = '1 0 0';
      }
      return styles;
    },
    getRowClass(row, rowIndex) {
      let className = this.rowClass;
      if (typeof className === 'function') {
        className = this.$triggerPropsFn('rowClass', row, rowIndex);
      }
      return this.$mergeClass({
        's-table__tr--stripe': this.stripe && rowIndex % 2,
      }, className);
    },
    getRowStyle(row, rowIndex) {
      let style = this.rowStyle;
      if (typeof style === 'function') {
        style = this.$triggerPropsFn('rowStyle', row, rowIndex);
      }
      return this.$mergeStyle(style);
    },
    getThClass(column, columnIndex) {
      let className = this.thClass;
      if (typeof className === 'function') {
        className = this.$triggerPropsFn('thClass', column, columnIndex);
      }
      return this.$mergeClass({
        [`s-table__th--align-${column.align}`]: column.align,
      }, className);
    },
    getThStyle(column, columnIndex) {
      let style = this.thStyle;
      if (typeof style === 'function') {
        style = this.$triggerPropsFn('thStyle', column, columnIndex);
      }
      return this.$mergeStyle(this.getColumnWidth(column), {
        borderColor: this.borderColor,
      }, style);
    },
    getTdClass(params) {
      const { column } = params;
      let className = this.tdClass;
      if (typeof className === 'function') {
        className = this.$triggerPropsFn('tdClass', params);
      }
      return this.$mergeClass({
        [`s-table__td--align-${column.align}`]: column.align,
      }, className);
    },
    getTdStyle(params) {
      let style = this.tdStyle;
      if (typeof style === 'function') {
        style = this.$triggerPropsFn('tdStyle', params);
      }
      return this.$mergeStyle(this.getColumnWidth(params.column), {
        borderColor: this.borderColor,
      }, style);
    },
    onThClick(column, columnIndex) {
      this.$emit('th-click', column, columnIndex);
      if (this.hasSort(column)) {
        if (this.sortBy !== column.sortBy) {
          this.$emit('update:sortBy', column.sortBy);
          this.$emit('update:sortOrder', 'asc');
        } else {
          if (!this.sortOrder) {
            this.$emit('update:sortOrder', 'asc');
          } else if (this.sortOrder === 'asc') {
            this.$emit('update:sortOrder', 'desc');
          } else if (this.sortOrder === 'desc') {
            this.$emit('update:sortBy', '');
            this.$emit('update:sortOrder', '');
          }
        }
        this.$emit('sort', column, columnIndex);
      }
    },
    onTrClick(row, rowIndex) {
      this.$emit('tr-click', row, rowIndex);
    },
    onTdClick(params) {
      this.$emit('td-click', params);
    },
  },
};
</script>

<style lang="scss" src="./index.scss"></style>
